=begin pod

=TITLE role IO

=SUBTITLE Input/output related routines

The role provides no methods, but exists so that C<IO()> coercers, which coerce
to L<IO::Path>, correctly type-check the resultant value. The role is done
by L<IO::Path> and L<IO::Special>.

=head1 Routines

=head2 sub chdir

Defined as:

    sub chdir(IO() $path, :$d = True, :$r, :$w, :$x --> IO::Path:D)

Changes value of C<$*CWD> variable to the provided C<$path>, optionally ensuring
the new path passes several file tests. B<NOTE:> that this routine does I<NOT>
alter the process's current directory (see
L«C<&*chdir>|/routine/&*chdir»).

Returns L«C<IO::Path>|/type/IO::Path»
representing new C<$*CWD> on success. On failure, returns
L«C<Failure>|/type/Failure» and leaves C<$*CWD> untouched.
The C<$path> can be any object with an IO method that returns an
L«C<IO::Path>|/type/IO::Path» object. The available file tests are:

=item C<:d> — check L«C<.d>|/routine/d» returns C<True>

=item C<:r> — check L«C<.r>|/routine/d» returns C<True>

=item C<:w> — check L«C<.w>|/routine/d» returns C<True>

=item C<:x> — check L«C<.x>|/routine/d» returns C<True>

By default, only C<:d> test is performed.

=for code
chdir         '/tmp'; # change $*CWD to '/tmp' and check its .d is True
chdir :r, :w, '/tmp'; # … check its .r and .w are True
chdir '/not-there';   # returns Failure

Note that the following construct is a mistake:

=for code
# WRONG! DO NOT DO THIS!
my $*CWD = chdir '/tmp/';

Use L«C<indir>|/routine/indir» instead.

=head2 sub &*chdir

Defined as:

=for code :skip-test
PROCESS:<&chdir> = sub (IO() $path --> IO::Path:D)

Changes value of C<$*CWD> variable to the provided C<$path> and sets
the process's current directory to the value of
L«C<$path.absolute>|/routine/absolute». B<NOTE:> that in most cases,
you want to use L«C<chdir>|/routine/chdir» routine instead.

Returns L«C<IO::Path>|/type/IO::Path»
representing new C<$*CWD> on success. On failure, returns
L«C<Failure>|/type/Failure» and leaves C<$*CWD> untouched.
The C<$path> can be any object with an IO method that returns an
L«C<IO::Path>|/type/IO::Path» object.

Note that unlike regular L«C<chdir>|/routine/chdir», there are no arguments
to specify which file tests to perform.

=for code
&*chdir('/tmp');  # change $*CWD and process's current directory to '/tmp'
&*chdir('/not-there'); # returns Failure

Note that the following construct is a mistake:

=for code
# WRONG! DO NOT DO THIS!
my $*CWD = &*chdir('/tmp');

Use the following, instead; or see L«C<indir>|/routine/indir» if
you do not need to change process's current directory:

=for code
temp $*CWD;
&*chdir('/tmp');

=head2 sub chmod

Defined as:

    sub chmod(Int() $mode, *@filenames --> List)

Coerces all C<@filenames> to L«C<IO::Path>|/type/IO::Path» and calls
L«C<IO::Path.chmod>|/type/IO::Path#method_chmod» with C<$mode> on them.
Returns a L«C<List>|/type/List» containing a subset of C<@filenames> for which
C<chmod> was successfully executed.

    chmod 0o755, <myfile1  myfile2>; # make two files executable by the owner

=head2 sub indir

Defined as:

    sub indir(IO() $path, &code, :$d = True, :$r, :$w, :$x --> Mu)

Takes L«C<Callable>|/type/Callable» C<&code> and executes it after locally (to
C<&code>) changing C<$*CWD> variable to an L<IO::Path> object based on C<$path>,
optionally ensuring the new path passes several file tests. If C<$path> is
relative, it will be turned into an absolute path, even if an L<IO::Path>
object was given. B<NOTE:> that this routine does I<NOT> alter the process's
current directory (see L«C<&*chdir>|/routine/&*chdir»). The C<$*CWD>
outside of the C<&code> is not affected, even if C<&code> explicitly assigns
a new value to C<$*CWD>.

Returns the return value of C<&code> on success. On failure to successfully
change C<$*CWD>, returns L«C<Failure>|/type/Failure». B<WARNING:> keep in
mind that lazily evaluated things might end up NOT having the C<$*CWD> set
by C<indir> in their dynamic scope by the time they're actually evaluated.
Either ensure the generators have their C<$*CWD> set or
L<eagerly evaluate|/routine/eager> them before returning the results from
C<indir>:

    say indir("/tmp", {
        gather { take ".".IO }
    })».CWD; # OUTPUT: «(/home/camelia)␤»

    say indir("/tmp", {
        eager gather { take ".".IO }
    })».CWD; # OUTPUT: «(/tmp)␤»

    say indir("/tmp", {
        my $cwd = $*CWD;
        gather { temp $*CWD = $cwd; take ".".IO }
    })».CWD; # OUTPUT: «(/tmp)␤»

The routine's C<$path> argument can be any object with an IO method that
returns an L«C<IO::Path>|/type/IO::Path» object. The available file
tests are:

=item C<:d> — check L«C<.d>|/routine/d» returns C<True>

=item C<:r> — check L«C<.r>|/routine/d» returns C<True>

=item C<:w> — check L«C<.w>|/routine/d» returns C<True>

=item C<:x> — check L«C<.x>|/routine/d» returns C<True>

By default, only C<:d> test is performed.

    say $*CWD;                   # OUTPUT: «"/home/camelia".IO␤»
    indir '/tmp', { say $*CWD }; # OUTPUT: «"/tmp".IO␤»
    say $*CWD;                   # OUTPUT: «"/home/camelia".IO␤»

    indir '/not-there', {;};     # returns Failure; path does not exist

=head2 sub print

Defined as:

    multi sub print(**@args --> True)

Prints the given text on standard output (the
L«C<$*OUT>|/language/variables#index-entry-%24%2AOUT» file handle), coercing
non-L<Str> objects to L<Str> by calling
L«C<.Str> method|/routine/Str»:

    print "Hi there!\n";   # OUTPUT: «Hi there!␤»
    print "Hi there!";     # OUTPUT: «Hi there!»
    print [1, 2, 3];       # OUTPUT: «1 2 3»

To print text and include the trailing newline, use L«C<put>|/type/IO#sub_put».

=head2 sub put

Defined as:

    multi sub put(**@args --> True)

Same as L«C<print>|/type/IO#sub_print», except appends
L«C<$*OUT.nl-out>|/type/IO::Handle#method_nl-out» (a newline, by default) at
the end:

    put "Hi there!\n";   # OUTPUT: «Hi there!␤␤»
    put "Hi there!";     # OUTPUT: «Hi there!␤»
    put [1, 2, 3];       # OUTPUT: «1 2 3␤»

=head2 sub say

Defined as:

    multi sub say(**@args --> True)

Prints the "gist" of given objects. Same as L«C<put>|/type/IO#sub_put», except
coerces non-L<Str> arguments using L«C<.gist>|/routine/gist» method.

B<NOTE:> the L«C<.gist>|/routine/gist» method of some objects, such as
L<Lists|/type/List#method_gist>, returns only B<partial> information about the
object (hence the "gist"). If you mean to print textual information,
you most likely want to use L«C<put>|/type/IO#sub_put» instead.

    say Range;        # OUTPUT: «(Range)␤»
    say class Foo {}; # OUTPUT: «(Foo)␤»
    say 'I ♥ Perl6';  # OUTPUT: «I ♥ Perl6␤»
    say 1..Inf;       # OUTPUT: «1..Inf␤»

=head2 routine note

Defined as:

    method note(Mu: -->Bool:D)
    multi sub note(            --> Bool:D)
    multi sub note(Str:D $note --> Bool:D)
    multi sub note(**@args     --> Bool:D)

Like L«C<say>|/routine/say», except prints output to L«C<$*ERR>|/language/variables#index-entry-%24%2AERR» handle (STDERR).
If no arguments are given to subroutine forms, will use string C<"Noted">.

=begin code
note;       # STDERR OUTPUT: «Noted␤»
note 'foo'; # STDERR OUTPUT: «foo␤»
note 1..*;  # STDERR OUTPUT: «1..Inf␤»
=end code

=head2 sub prompt

    multi prompt()
    multi prompt($msg)

L<Prints|/routine/print> C<$msg> to C<$*OUT> handle, if C<$msg> was provided,
then L<gets|/routine/get> a line of input from C<$*IN> handle. By default,
this is equivalent to printing C<$msg> to
L<STDOUT|https://en.wikipedia.org/wiki/Standard_streams#Standard_output_.28stdout.29>, reading a line from
L<STDIN|https://en.wikipedia.org/wiki/Standard_streams#Standard_input_.28stdin.29>,
removing the trailing new line, and returning the resultant string.

=for code
my $name = prompt "What's your name? ";
say "Hi, $name! Nice to meet you!";

=head2 sub open

    multi sub open(IO() $path, |args --> IO::Handle:D)

Creates L<a handle|/type/IO::Handle> with the given C<$path>, and calls
L«C<IO::Handle.open>|/type/IO::Handle», passing any of the remaining arguments
to it. Note that L<IO::Path> type provides numerous methods for reading and
writing from files, so in many common cases you do not need to C<open> files
or deal with L<IO::Handle> type directly.

=begin code
my $fh = open :w, '/tmp/some-file.txt';
$fh.say: 'I ♥ writing Perl code';
$fh.close;

$fh = open '/tmp/some-file.txt';
print $fh.readchars: 4;
$fh.seek: 7, SeekFromCurrent;
say $fh.readchars: 4;
$fh.close;

# OUTPUT: «I ♥ Perl␤»
=end code

=head2 sub slurp

Slurps the contents of the entire file into a C<Str> (or C<Buf> if C<:bin>).
Accepts C<:bin> and C<:enc> optional named parameters, with the same meaning
as L<open()|/routine/open>.  The routine will C<fail> if the file does not
exist, or is a directory.

=begin code :skip-test
# read entire file as (Unicode) Str
my $text_contents   = slurp "path/to/file";

# read entire file as Latin1 Str
my $text_contents   = slurp "path/to/file", enc => "latin1";

# read entire file as Buf
my $binary_contents = slurp "path/to/file", :bin;
=end code

=head2 sub spurt

Defined as:

    multi spurt(IO() $path, |c)

The C<$path> can be any object with an IO method that returns an
L«C<IO::Path>|/type/IO::Path» object. Calls L«C<IO::Path.spurt>|/routine/spurt»
on the C<$path>, forwarding any of the remaining arguments.

=head3 Options

=item :enc

The encoding with which the contents will be written.

=item :bin

Open the file in binary mode.

=item :append

Boolean indicating whether to append to a (potentially) existing file.  If
the file did not exist yet, it will be created.  Defaults to C<False>.

=item :createonly

Boolean indicating whether to fail if the file already exists.  Defaults to
C<False>.

=head3 Examples

=begin code
# write directly to a file
spurt 'path/to/file', 'default text, directly written';

# write directly with a non-Unicode encoding
spurt 'path/to/latin1_file', 'latin1 text: äöüß', :enc<latin1>;

spurt 'file-that-already-exists', 'some text';           # overwrite file's contents:
spurt 'file-that-already-exists', ' new text', :append;  # append to file's contents:
say slurp 'file-that-already-exists';                    # OUTPUT: «some text new text␤»

# fail when writing to a pre-existing file
spurt 'file-that-already-exists', 'new text', :createonly;
# OUTPUT: «Failed to open file /home/camelia/file-that-already-exists: file already exists …»
=end code

=head2 sub run

    sub run(*@args ($, *@) --> Proc)

Runs an external command without involving a shell and returns a L<Proc> object.

    run 'touch', '>foo.txt'; # Create a file named >foo.txt

    run Q:w{rm >foo.txt}; # Another way to use run, using word quoting for the
                          # arguments

A sunk L<Proc> object for a process that L<exited|/routine/exitcode> unsuccessfully
will throw. If you wish to ignore such failures, simply use L<run> in non-sink context:

    run 'false';     # SUNK! Will throw
    run('false').so; # OK. Evaluates Proc in Bool context; no sinking

To capture output or error you can use the C<:out> or C<:err> arguments respectively:

    my $proc = run 'echo', 'Perl 6 is Great!', :out, :err;
    $proc.out.slurp(:close).say; # OUTPUT: «Perl 6 is Great!␤»
    $proc.err.slurp(:close).say; # OUTPUT: «␤»

See L<Proc|/type/Proc> and L<Proc::Async|/type/Proc::Async> for more details.

=head2 sub shell

    sub shell($cmd --> Proc)

Runs a command through the system shell. All shell meta characters are
interpreted by the shell, including pipes, redirects, environment variable
substitutions and so on. Shell escapes are a severe security concern and can
cause confusion with unusual file names. Use L<run|/type/IO#sub_run> if you
want to be safe.

The return value is of L<type Proc|/type/Proc>.

    shell 'ls -lR | gzip -9 > ls-lR.gz';

See L<Proc|/type/Proc> for more details, for example on how to capture
output.

=head1 Related classes

See also the related classes L<IO::Handle> and L<IO::Path>.

=end pod

# vim: expandtab softtabstop=4 shiftwidth=4 ft=perl6
